// Mesh Scene Node
// (c) jimon game studio

#include "CMeshSceneNode.h"

namespace je
{
	namespace scene
	{
		//! Constructor
		CMeshSceneNode::CMeshSceneNode(video::IRender * Render,scene::ISceneManager * SceneManager)
			:IMeshSceneNode(Render,"MeshSceneNode"),CurrentSceneManager(SceneManager),CurrentSharedMesh(NULL),CurrentUseUniqueMesh(false),MeshRadius(0.0f),EnableAnimation(false),SkinnedMesh(NULL),NeedRecalculateAnimation(true)
		{
		}

		//! Destructor
		CMeshSceneNode::~CMeshSceneNode()
		{
			if(SkinnedMesh)
				SkinnedMesh->Drop();

			SetMeshResource(NULL);
		}

		//! Set Mesh Resource
		void CMeshSceneNode::SetMeshResource(media::jeMeshResource * MeshResource,u1 UseUniqueMesh)
		{
			if(CurrentSharedMesh)
			{
				CurrentSceneManager->UnRegisterNodeFromRenderingQueue(this,CurrentSharedMesh->GetMesh()->IsThereAllMaterialsAreTransparent() ? RPG_TRANSPARENT : RPG_SOLID);

				if(CurrentUseUniqueMesh)
					JE_MESHRESOURCE_DROP(CurrentSharedMesh,this,CurrentRender)
				else
					JE_MESHRESOURCE_SHARED_DROP(CurrentSharedMesh,CurrentRender)

				CurrentSharedMesh = NULL;
			}

			CurrentUseUniqueMesh = UseUniqueMesh;

			if(MeshResource)
			{
				if(CurrentUseUniqueMesh)
					JE_MESHRESOURCE_GRAB(CurrentSharedMesh,MeshResource,this,CurrentRender)
				else
					JE_MESHRESOURCE_SHARED_GRAB(CurrentSharedMesh,MeshResource,CurrentRender)

				CurrentSceneManager->RegisterNodeInRenderingQueue(this,CurrentSharedMesh->GetMesh()->IsThereAllMaterialsAreTransparent() ? RPG_TRANSPARENT : RPG_SOLID);
				MeshRadius = CalculateInsphereRadiusMesh(CurrentSharedMesh->GetMesh());

				if(CurrentSharedMesh->GetMesh()->IsThereSkeleton())
				{
					JENEW(SkinnedMesh,CSkinnedMesh(CurrentSharedMesh->GetMesh()->GetMeshWithSkeleton(),CurrentRender))
					EnableAnimation = true;
				}
			}
		}

		//! Get Mesh Resource
		media::jeMeshResource * CMeshSceneNode::GetMeshResource()
		{
			if(CurrentSharedMesh)
				return JE_MESHRESOURCE(CurrentSharedMesh->GetResourceName());
			else
				return NULL;
		}

		//! Get Shared Mesh Resource
		media::jeSharedMesh * CMeshSceneNode::GetSharedMeshResource()
		{
			return CurrentSharedMesh;
		}

		//! On Update
		void CMeshSceneNode::OnUpdate()
		{
			ISceneNode::OnUpdate();
		}

		//! On Render
		void CMeshSceneNode::OnRender()
		{
			if(EnableAnimation)
				if(NeedRecalculateAnimation)
				{
					SkinnedMesh->SoftwareCalculateSkin(CurrentAnimation.Id,CurrentAnimation.Time);
					NeedRecalculateAnimation = false;
				}

			CurrentRender->SetMatrix(TextureMatrix,video::RMT_TEXTURE);
			CurrentSharedMesh->GetMesh()->OnRender(AbsoluteModelMatrix);

			if(EnableAnimation)
				SkinnedMesh->SoftwareRestoreArrays();

			ISceneNode::OnRender();
		}

		//! On Visibility Culling
		void CMeshSceneNode::OnVisibilityCulling()
		{
			InFrame = CurrentSceneManager->GetCurrentCamera()->GetFrustum()->IsSphereIn(AbsoluteModelMatrix.GetTranslation(),MeshRadius*AbsoluteScale.GetMaxComponent());
			ISceneNode::OnVisibilityCulling();
		}

		//! Serialize
		void CMeshSceneNode::Serialize(core::ISerializeStream * SerializeStream)
		{
			JE_SS_BEGIN(MeshSceneNode)

			jeStringc MeshResourceName;

			if(JE_SS_SAVE && CurrentSharedMesh)
				MeshResourceName = CurrentSharedMesh->GetResourceName();

			JE_SS(MeshResourceName)

			JE_SS_SIZE(CurrentAnimation,sizeof(MeshAnimation))
			JE_SS_END(MeshSceneNode)

			if(JE_SS_LOAD)
				SetMeshResource(JE_MESHRESOURCE(MeshResourceName));

			ISceneNode::Serialize(SerializeStream);
		}

	}
}
